package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

type Person struct {
	Name string
	age  int
}

func (p *Person) Show() {
	fmt.Println("this is show method")
}
func NewPerson(name string, age int) *Person {
	return &Person{
		Name: name,
		age:  age,
	}
}

/**
反射调用方法
*/
func structMethod(v interface{}) {
	// 反射方法
	dataType := reflect.TypeOf(v)
	dataValue := reflect.ValueOf(v)
	num := dataType.NumMethod()

	for i = 0; i < num; i++ {
		name := dataType.Method(i).Name
		methodValue := dataValue.MethodByName(name)
		if !methodValue.IsValid() {
			fmt.Println(name + "is not valid")
			continue
		}
		methodValue.Call(nil)
	}
}

/**
反射获取字段和设置字段
*/
func simpleStructField(v interface{}) {
	dataType := reflect.TypeOf(v)
	dataValue := reflect.ValueOf(v)

	if dataType.Kind() == reflect.Ptr { //指针类型
		if dataValue.IsNil() { //是否是空指针
			panic("nil ptr")
		}
		// 如果是指针，则要判断一下是否为struct
		originType := reflect.ValueOf(v).Elem().Type()
		if originType.Kind() != reflect.Struct { //不是结构体则返回
			return
		}
		// 解引用
		dataValue = dataValue.Elem()
		dataType = dataType.Elem()
	} else {
		panic("non ptr")
	}

	// 反射字段
	num := dataType.NumField()

	for i = 0; i < num; i++ {
		field := dataType.Field(i)
		fieldName := field.Name

		fieldValue := dataValue.FieldByName(fieldName)
		if !fieldValue.IsValid() {
			continue
		}
		if fieldValue.CanInterface() {
			fmt.Printf("exported fieldName:%v value:%v\n", fieldName, fieldValue.Interface())
			if fieldValue.CanSet() && fieldValue.Kind() == reflect.String {
				oldValue := fieldValue.Interface().(string)
				fieldValue.SetString(oldValue + " auto append")
			}
		} else {
			// 强行取址
			forceValue := reflect.NewAt(fieldValue.Type(), unsafe.Pointer(fieldValue.UnsafeAddr())).Elem()
			fmt.Printf("unexported fieldName:%v value:%v\n", fieldName, forceValue.Interface())
		}
	}

}

func main44() {
	person := NewPerson("Lisi", 23)
	structMethod(person)
	simpleStructField(person)
	fmt.Println(*person)
}
